const Joi = require('joi')
const { Op } = require('sequelize')
const R = require('@/models/Response')
const { Source, BinSource, Share } = require('@/models/model')
const {
  ERROR_SYSTEM_CODE,
  ERROR_SOURCE_CODE
} = require('@/constants/errorCode')
const { IS_INTEGER, IS_UNSAFE_INTEGER } = require('@/constants/joiSchema')
const { SEPARATE_CHAR } = require('@/constants/index')
const {
  formatFilename,
  formatFilenameByInc,
  getNumName
} = require('@/utils/format')
const { dumpCheck: globalDumpCheck } = require('@/utils/dumpCheck')
const {
  commonVerifySourceAuth,
  commonVerifySourcesAuth
} = require('../authMiddlewares/verifySourceAuth')
const UserOption = require('@/models/userOptionModel')

const sourceSchema = {
  page: IS_INTEGER.min(1).default(1),
  pageSize: IS_INTEGER.min(1).default(999),
  // 文件类型（0 文件夹,1 普通文件 2 压缩文件 3 excel 4 word 5 pdf 6 txt 7 图片 8 音频 9 视频 10 ppt 11 源码文件 12 csv,13 md）
  type: IS_INTEGER.valid(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
  isDir: IS_INTEGER.valid(0, 1),
  deleteFlag: IS_INTEGER.valid(0, 1).default(0),
  filename: Joi.string().min(1).max(50),
  parentId: IS_UNSAFE_INTEGER,
  shareId: IS_UNSAFE_INTEGER,
  sourceIds: Joi.array().items(IS_UNSAFE_INTEGER),
  sourceId: IS_UNSAFE_INTEGER,
  authTo: Joi.array().items(
    Joi.object({
      targetType: IS_INTEGER.valid(1, 2).required(),
      targetId: IS_UNSAFE_INTEGER.required(),
      roleId: IS_UNSAFE_INTEGER.required()
    })
  )
}

// 字段重复验证
const dumpCheck = {
  /**
   * 校验目录ID是否正确，目录ID要么为-1，要么为source的id,且不能被删除，如果父级的父级被删除了呢？ 递归
   * 用户可访问的pid(targetId为用户的，且是自己的)
   * (targetId为部门的，用户对该source拥有权限，或者用户在该部门的权限正确)
   * @param {*} ctx
   * @param {string} parentId   父级id
   * @param {boolean} deleteFlag 是否被删除
   * @returns {Promise<boolean>}
   */
  checkParentId: async (ctx, parentId, deleteFlag = 0) => {
    return dumpCheck.checkFileIds(ctx, [parentId], deleteFlag, true)
  },

  /**
   * 检验filename是否重复
   * @param {*} ctx
   * @param {string} parentId 父级资源ID
   * @param {string} filename 文件名称
   * @returns {Promise<boolean>}
   */
  checkFilename: async (ctx, parentId, filename) => {
    const source = await Source.findOne({
      where: {
        parentId: BigInt(parentId),
        filename,
        deleteFlag: 0
      }
    })

    // 说明文件名已经存在
    if (source) {
      return false
    }

    return true
  },

  /**
   * 检验sourceid存在且不重复，
   * 1. 没有被删除，其父级目录也没有被删除
   * 2. 被删除，不要求其父级
   * @param {*} ctx
   * @param {*} sourceIds 资源id数组
   * @param {number} deleteFlag 是否删除
   * @param {boolean} ingoreRootId 是否忽略根source-1
   */
  checkFileIds: async (
    ctx,
    sourceIds,
    deleteFlag = 0,
    ingoreRootId = false
  ) => {
    let newSourceIds = [...new Set(sourceIds)]

    //  重复
    if (newSourceIds.length !== sourceIds.length) {
      return false
    }

    if (ingoreRootId) {
      newSourceIds = newSourceIds.filter((item2) => +item2 !== -1)
    }

    // 证明为空数组或者[-1,-1,-1]
    if (!newSourceIds.length) {
      return true
    }

    newSourceIds = newSourceIds.map((item) => BigInt(item))

    let files = await Source.findAll({
      where: {
        id: {
          [Op.in]: newSourceIds
        },
        deleteFlag
      },
      attribute: ['parentId']
    })

    // 用户文件ID数组有误
    if (files.length !== newSourceIds.length) {
      return false
    }

    if (deleteFlag) {
      // 到这里就可以了,本身删除就行
      return true
    } else {
      // 需要保证其父级也没有被删除
      // 验证父级目录是否被删除，因为到这里只能说明自身deleteFlag字段为0，如果父级目录flag为1呢
      let parentIds = files
        .map((item) => item.parentId)
        .filter((item2) => +item2 !== -1)
      // 有些source的parentId直接为-1了，肯定查不到，所以得忽略-1
      // 看parentIds是否正确

      // 大家的parentId可以是同一个
      parentIds = [...new Set(parentIds)].map((item3) => BigInt(item3))

      if (!parentIds.length) {
        return true
      }

      let files2 = await Source.findAll({
        where: {
          id: {
            [Op.in]: parentIds
          },
          deleteFlag
        },
        attribute: ['parentId']
      })

      if (files2.length !== parentIds.length) {
        return false
      }
      return true
    }
  }
}

module.exports.checkParentId = dumpCheck.checkParentId

/**
 * 检验用户查询文件列表接口的参数
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listSourceValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: sourceSchema.page,
    pageSize: sourceSchema.pageSize,
    type: sourceSchema.type,
    isDir: sourceSchema.isDir,
    deleteFlag: sourceSchema.deleteFlag,
    filename: Joi.string().allow(''),
    parentId: sourceSchema.parentId.required()
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // 将转化后的格式付给query
  ctx.newQuery = schema.value
  await next()
}

/**
 * 检验用户查询外链分享的文件列表接口的参数
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listLinkShareSourceValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: sourceSchema.page,
    pageSize: sourceSchema.pageSize,
    type: sourceSchema.type,
    isDir: sourceSchema.isDir,
    deleteFlag: sourceSchema.deleteFlag,
    filename: Joi.string().allow(''),
    parentId: sourceSchema.parentId.required(),
    shareId: sourceSchema.shareId.required(),
    code: Joi.string().min(0).max(20)
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { shareId, code, page, pageSize, parentId } = ctx.query
  // 验证shareId以及密码的合法性
  const share = await Share.findByPk(BigInt(shareId), {
    include: [
      {
        model: Source,
        as: 'source'
      }
    ]
  })
  if (!share) {
    ctx.body = R.success({
      page,
      pageSize,
      items: [],
      total: 0,
      curSource: null,
      pages: 0
    })
    return
  }

  // 看是否需要密码
  if (share.code !== '') {
    if (share.code !== code) {
      ctx.body = R.success({
        page,
        pageSize,
        items: [],
        total: 0,
        curSource: null,
        pages: 0
      })
      return
    }
  }

  // 看传入的parentId是否为shareSource的子代
  const pSource = await Source.findByPk(BigInt(parentId))
  if (!pSource) {
    ctx.body = R.success({
      page,
      pageSize,
      items: [],
      total: 0,
      curSource: null,
      pages: 0
    })
    return
  }

  const pSourceLevel = pSource.parentLevel + SEPARATE_CHAR + pSource.id

  if (!pSourceLevel.includes(share.sourceId)) {
    ctx.body = R.success({
      page,
      pageSize,
      items: [],
      total: 0,
      curSource: null,
      pages: 0
    })
    return
  }
  // 将转化后的格式付给query
  ctx.newQuery = schema.value
  await next()
}

/**
 * 检验用户根据sourceId查询文件列表接口的参数
 * @param {*} ctx
 * @param {*} next
 * @returns
 */

module.exports.listSourceByIdValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceId: sourceSchema.sourceId.required()
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  ctx.newQuery = schema.value

  const { sourceId } = ctx.query

  const source = await Source.findByPk(sourceId)
  if (!source) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  // 如果资源类型为部门文件，需要判断用户是否拥有预览权限
  if (+source.targetType === 2) {
    const b = await commonVerifySourceAuth(ctx.user.id, source.id, [
      'doc.auth.view'
    ])

    if (!b) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  await next()
}

/**
 * 检验用户根据sourceId查询文件日志接口的参数
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listSourceLogByIdValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: sourceSchema.page,
    pageSize: sourceSchema.pageSize,
    sourceId: sourceSchema.sourceId.required()
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  ctx.newQuery = schema.value

  const { sourceId } = ctx.query

  const source = await Source.findByPk(sourceId)
  if (!source) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  // 如果资源类型为部门文件，需要判断用户是否拥有预览权限
  if (+source.targetType === 2) {
    const b = await commonVerifySourceAuth(ctx.user.id, source.id, [
      'doc.auth.view'
    ])

    if (!b) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  await next()
}

/**
 * 根据文件类型进行查询的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listFileTypeSourceValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: sourceSchema.page,
    pageSize: sourceSchema.pageSize,
    filename: Joi.string().allow(''),
    fileType: Joi.string()
      .valid(
        '{userFileType:doc}',
        '{userFileType:image}',
        '{userFileType:music}',
        '{userFileType:movie}',
        '{userFileType:zip}',
        '{userFileType:others}'
      )
      .required()
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // 将转化后的格式付给query
  ctx.newQuery = schema.value
  await next()
}

/**
 * 根据文件类型进行查询的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listBinSourceValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: sourceSchema.page,
    pageSize: sourceSchema.pageSize,
    filename: Joi.string().allow('')
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // 将转化后的格式付给query
  ctx.newQuery = schema.value
  await next()
}

/**
 * 校验新建文件夹接口的参数
 * @param {*} ctx
 * @param {*} next
 */
module.exports.createDirValidate = async (ctx, next) => {
  const schema = Joi.object({
    dirName: sourceSchema.filename.required(),
    parentId: sourceSchema.parentId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // 验证filename是否重复，验证传递的parentId是否为当前用户的目录ID
  const { dirName, parentId } = ctx.request.body
  const b1 = await dumpCheck.checkParentId(ctx, parentId)
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.PARENT_ID_ERROR)
    return
  }

  // 验证用户对部门资源是否拥有权限
  const source = await Source.findByPk(BigInt(parentId))
  if (!source) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }
  // 如果资源类型为部门文件，需要判断用户是否拥有预览权限
  if (+source.targetType === 2) {
    const b = await commonVerifySourceAuth(ctx.user.id, source.id, [
      'doc.auth.edit'
    ])

    if (!b) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  // 查询当前目录中是否存在同名文件
  const b2 = await dumpCheck.checkFilename(ctx, parentId, dirName)
  if (!b2) {
    // 获取用户配置
    const one = await UserOption.findOne({
      where: {
        key: 'renameFormat',
        userId: ctx.user.id
      }
    })
    // 重复了，解决冲突，使用文件夹递增的方式解决，根据用户配置来进行重名文件的处理
    // 加上时间戳
    if (!one) {
      ctx.request.body.dirName = formatFilename(dirName)
    } else {
      if (+one.value === 1) {
        ctx.request.body.dirName = await formatFilename(dirName, true)(
          parentId,
          dirName
        )
      }
    }
  }
  await next()
}

/**
 * 校验新建文件接口的参数
 * @param {*} ctx
 * @param {*} next
 */
module.exports.createFileValidate = async (ctx, next) => {
  const schema = Joi.object({
    filename: sourceSchema.filename.required(),
    parentId: sourceSchema.parentId.required(),
    type: sourceSchema.type.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // 验证filename是否重复，验证传递的parentId是否为当前用户的目录ID
  const { filename, parentId } = ctx.request.body
  const b1 = await dumpCheck.checkParentId(ctx, parentId)
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.PARENT_ID_ERROR)
    return
  }

  // 验证用户对部门资源是否拥有权限
  const source = await Source.findByPk(BigInt(parentId))
  if (!source) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }
  // 如果资源类型为部门文件，需要判断用户是否拥有新建权限
  if (+source.targetType === 2) {
    const b = await commonVerifySourceAuth(ctx.user.id, source.id, [
      'doc.auth.edit'
    ])

    if (!b) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  // 查询当前目录中是否存在同名文件
  const b2 = await dumpCheck.checkFilename(ctx, parentId, filename)
  if (!b2) {
    // 重复了，解决冲突，使用文件夹递增的方式解决，根据用户配置来进行重名文件的处理
    const one = await UserOption.findOne({
      where: {
        key: 'renameFormat',
        userId: ctx.user.id
      }
    })
    if (!one) {
      ctx.request.body.filename = formatFilename(filename)
    } else {
      if (+one.value === 1) {
        ctx.request.body.filename = await formatFilename(filename, true)(
          parentId,
          filename
        )
      }
    }
  }
  await next()
}

/**
 * 文件重命名接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.renameValidate = async (ctx, next) => {
  const schema = Joi.object({
    filename: sourceSchema.filename.required(),
    sourceId: sourceSchema.sourceId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { filename, sourceId } = ctx.request.body
  // 验证sourceId的合法性
  const b1 = await dumpCheck.checkFileIds(ctx, [sourceId])
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  const source = await Source.findOne({
    where: {
      id: BigInt(sourceId),
      deleteFlag: 0
    },
    attributes: ['id', 'parentId', 'filename', 'targetType']
  })

  // 验证用户对部门资源是否拥有权限
  if (!source) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }
  // 如果资源类型为部门文件，需要判断用户是否拥有编辑权限
  if (+source.targetType === 2) {
    const b = await commonVerifySourceAuth(ctx.user.id, source.id, [
      'doc.auth.edit'
    ])

    if (!b) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  // 验证filename是否重复
  const b2 = await dumpCheck.checkFilename(ctx, source.parentId, filename)
  if (!b2 && source.filename !== filename) {
    // 文件名重复了
    ctx.body = R.error(ERROR_SOURCE_CODE.FILENAME_DUMP_ERROR)
    return
  }

  await next()
}

/**
 * 多个文件移动接口的参数验证
 * 这个验证同时适应于多个文件复制接口
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.moveFileValidate = async (ctx, next) => {
  const schema = Joi.object({
    parentId: sourceSchema.parentId.required(),
    sourceIds: sourceSchema.sourceIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { parentId, sourceIds } = ctx.request.body

  // 验证目标目录ID的合法性
  const b2 = await dumpCheck.checkParentId(ctx, parentId)
  if (!b2) {
    ctx.body = R.error(ERROR_SOURCE_CODE.PARENT_ID_ERROR)
    return
  }

  // 验证传入的sourceids是否存在错误
  const b1 = await dumpCheck.checkFileIds(ctx, sourceIds)
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  // 目标sourceId中不能存在其为parentId本身，或者其为parentId的父亲

  const parentSource = await Source.findByPk(BigInt(parentId))
  const pids = [...parentSource.parentLevel.split(SEPARATE_CHAR), parentId]

  let sources = await Source.findAll({
    where: {
      id: {
        [Op.in]: sourceIds
      },
      deleteFlag: 0
    },
    attribute: ['id', 'targetType']
  })
  let fileIds = sources.map((item) => item.id)

  const isDump = fileIds.some((item) => {
    return pids.includes(item)
  })

  if (isDump) {
    // 说明存在一个id为parentId的父亲，不行
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  // 对parentId，如果为部门文件，需要拥有move权限
  // 对sourceIds，如果为部门文件，也需要move权限
  let needVerift = []
  if (+parentSource.targetType === 2) {
    needVerift.push(parentSource.id)
  }

  needVerift = needVerift.concat(
    sources.filter((item) => +item.type === 2).map((item) => item.id)
  )

  if (needVerift.length) {
    // 验证是否拥有move权限
    const res = await commonVerifySourcesAuth(ctx.user.id, needVerift, [
      'doc.auth.download/copy'
    ])

    if (!res) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  // // 存在同一目录的文件,不能移动到本目录
  // if (files.findIndex((item) => item.parentId === parentId) !== -1) {
  //   ctx.body = R.error(ERROR_SOURCE_CODE.MOVE_PARENTID_SAME_ERROR)
  //   return
  // }

  // 看是否存在同名文件，当前移动的文件和目标目录（parentID）下的文件是否重名
  // 除了和数据库的进行比较，还要和当前传递过来的文件列表比较
  // 对files根据filename进行去重
  /**
   *  {
   *      filename1:[{source1,type,id},{source1,type,id}],
   *      filename2:[xxx,xxx...]
   *  }
   */
  // files = JSON.parse(JSON.stringify(files))
  // sources = sources.map((item) => {
  //   item.entity = files.find((item2) => item2.id === item.id)
  //   return item
  // })
  // const unqiueArr = sources.reduce((pre, cur) => {
  //   pre[cur.entity.filename]
  //     ? pre[cur.entity.filename].push(cur)
  //     : (pre[cur.entity.filename] = [cur])
  //   return pre
  // }, {})

  // // 根据去重后的文件名给数组里面的名字赋予新值
  // for (const key in unqiueArr) {
  //   let num = await formatFilenameByInc(ctx.user.id, parentId, key, true)
  //   let start = 0
  //   let dump = null
  //   let sourceArr = unqiueArr[key]

  //   if (num === 0) {
  //     // 说明没有重名，以后覆盖的重名文件即为第一项
  //     dump = sourceArr[0].entity
  //     start++
  //     num = 1
  //     sourceArr[0].entity.dump = null
  //   } else {
  //     // 说明存在重名，查出重名实体
  //     dump = await Source.findOne({
  //       where: {
  //         userId: BigInt(ctx.user.id),
  //         parentId: BigInt(parentId),
  //         filename: key,
  //         deleteFlag: 0
  //       }
  //     })
  //   }
  //   let cnt = 0
  //   // 没有重名，从第二项开始处理
  //   // 重名了，从第一项开始处理
  //   // 这个for循环只要执行了1次及以上，都是重名情况
  //   for (let i = start; i < sourceArr.length; i++) {
  //     // 对于type===2的，也就是创建副本的，进行新名字获取
  //     // 对于type===1的，也就是覆盖的，添加覆盖实体
  //     if (+sourceArr[i].type === 2) {
  //       let newFilename = getNumName(key, num + cnt)
  //       sourceArr[i].entity.myfilename = newFilename
  //       sourceArr[i].entity.dump = dump
  //       cnt++
  //     } else if (+sourceArr[i].type === 1) {
  //       sourceArr[i].entity.dump = dump
  //     }
  //   }
  // }
  // 到这里就进行了预先查询，保证文件不会重名，且覆盖关系明确
  await next()
}

/**
 * 用户彻底删除多文件的参数验证,清空回收站
 * @param {*} ctx
 * @param {*} next
 */
module.exports.delFileValidate = async (ctx, next) => {
  const schema = Joi.object({
    isAll: Joi.number().valid(0, 1).required(),
    binSourceIds: Joi.when('isAll', {
      is: 0,
      then: sourceSchema.sourceIds.required(),
      otherwise: sourceSchema.sourceIds
    })
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { binSourceIds, isAll } = ctx.request.body

  if (+isAll === 0) {
    // 验证文件ID数组是否正确
    // 验证传入的binSourceIds是否正确，createUser都是当前用户
    const b1 = await globalDumpCheck.checkBinSourceIds(binSourceIds, [
      { field: 'createUser', value: BigInt(ctx.user.id) }
    ])
    if (!b1) {
      ctx.body = R.error(ERROR_SOURCE_CODE.BIN_SOURCE_ID_ERROR)
      return
    }

    // 如果是部门文件，需要有删除的权限
    const binSources = await BinSource.findAll({
      where: {
        id: {
          [Op.in]: binSourceIds
        },
        targetType: 2
      }
    })

    if (binSources.length) {
      const sourceIds = binSources.map((item) => item.sourceId)
      const res = await commonVerifySourcesAuth(ctx.user.id, sourceIds, [
        'doc.auth.remove'
      ])
      if (!res) {
        ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
        return
      }
    }
  }

  await next()
}

/**
 * 用户多文件放入回收站的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.binFileValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceIds: sourceSchema.sourceIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { sourceIds } = ctx.request.body

  // 验证文件ID数组是否正确
  // 验证传入的sourceids是否正确，本身没有被删除，且父级目录也没有被删除，且存在不重复
  sourceIds = sourceIds.map((item) => BigInt(item))
  const b1 = await dumpCheck.checkFileIds(ctx, sourceIds)
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
  }

  // 对于部门文件，看是否拥有删除的权限
  const depSources = await Source.findAll({
    where: {
      id: {
        [Op.in]: sourceIds
      },
      targetType: 2
    }
  })

  if (depSources.length) {
    // 需要验证权限
    const res = await commonVerifySourcesAuth(
      ctx.user.id,
      depSources.map((item) => item.id),
      ['doc.auth.remove']
    )

    if (!res) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  await next()
}

/**
 * 文件还原接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.recFileValidate = async (ctx, next) => {
  const schema = Joi.object({
    isAll: Joi.number().valid(0, 1).required(),
    binSourceIds: Joi.when('isAll', {
      is: 0,
      then: sourceSchema.sourceIds.required(),
      otherwise: sourceSchema.sourceIds
    })
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { binSourceIds, isAll } = ctx.request.body

  if (!isAll) {
    // 验证文件ID数组是否正确
    // 验证传入的binSourceIds是否正确，createUser都是当前用户
    const b1 = await globalDumpCheck.checkBinSourceIds(binSourceIds, [
      { field: 'createUser', value: BigInt(ctx.user.id) }
    ])
    if (!b1) {
      ctx.body = R.error(ERROR_SOURCE_CODE.BIN_SOURCE_ID_ERROR)
      return
    }

    // 如果是部门文件，需要有删除的权限
    const binSources = await BinSource.findAll({
      where: {
        id: {
          [Op.in]: binSourceIds
        },
        targetType: 2
      }
    })

    if (binSources.length) {
      const sourceIds = binSources.map((item) => item.sourceId)
      const res = await commonVerifySourcesAuth(ctx.user.id, sourceIds, [
        'doc.auth.remove'
      ])
      if (!res) {
        ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
        return
      }
    }
  }

  await next()
}

/**
 * 文件zip打包下载的接口验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.zipDownloadValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceIds: sourceSchema.sourceIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { sourceIds } = ctx.request.body

  // 验证sourceIds的合法性
  const b1 = await dumpCheck.checkFileIds(ctx, sourceIds)
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  // 对于部门文件，看是否拥有下载的权限
  const depSources = await Source.findAll({
    where: {
      id: {
        [Op.in]: sourceIds
      },
      targetType: 2
    }
  })

  if (depSources.length) {
    // 检查权限
    const res = await commonVerifySourcesAuth(
      ctx.user.id,
      depSources.map((item) => item.id),
      ['doc.auth.download/copy']
    )

    if (!res) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  await next()
}

/**
 * 单文件下载的接口验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.fileDownloadValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceId: sourceSchema.sourceId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { sourceId } = ctx.request.body

  // 验证sourceId的合法性,需要没有删除，且为文件类型
  const one = await Source.findOne({
    where: {
      id: BigInt(sourceId),
      deleteFlag: 0,
      isDir: 0
    }
  })

  if (!one) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  // 如果是部门文件，需要看是否存在下载的权限
  if (+one.targetType === 2) {
    const res = await commonVerifySourceAuth(ctx.user.id, one.id, [
      'doc.auth.download/copy'
    ])

    if (!res) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  await next()
}

/**
 * 文件授权接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.authSourceValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceId: sourceSchema.sourceId.required(),
    authTo: sourceSchema.authTo.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { sourceId } = ctx.request.body
  // 验证sourceId的合法性
  const b1 = await dumpCheck.checkFileIds(ctx, [sourceId])
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }

  const source = await Source.findOne({
    where: {
      id: BigInt(sourceId),
      deleteFlag: 0
    },
    attributes: ['id', 'parentId', 'filename', 'targetType']
  })

  // 验证用户对部门资源是否拥有权限
  if (!source) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
    return
  }
  // 如果资源类型为部门文件，需要判断用户是否拥有编辑权限
  if (+source.targetType === 2) {
    const b = await commonVerifySourceAuth(ctx.user.id, source.id, [
      'doc.auth.manage'
    ])

    if (!b) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  // TODO验证authTo的合法性
  await next()
}

/**
 * 获取当前用户对传入文件权限数组的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.getSourceAuthValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceIds: sourceSchema.sourceIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { sourceIds } = ctx.request.body

  // 验证文件ID数组是否正确
  // 验证传入的sourceids是否正确，本身没有被删除，且父级目录也没有被删除，且存在不重复
  sourceIds = sourceIds.map((item) => BigInt(item))
  const b1 = await dumpCheck.checkFileIds(ctx, sourceIds)
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
  }

  await next()
}

/**
 * 获取当前用户对传入文件权限数组的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.getSourceRoleValidate = async (ctx, next) => {
  const schema = Joi.object({
    sourceId: sourceSchema.sourceId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  let { sourceId } = ctx.request.body

  // 验证文件ID数组是否正确
  // 验证传入的sourceids是否正确，本身没有被删除，且父级目录也没有被删除，且存在不重复
  const b1 = await dumpCheck.checkFileIds(ctx, [sourceId])
  if (!b1) {
    ctx.body = R.error(ERROR_SOURCE_CODE.SOURCE_ID_ERROR)
  }

  await next()
}
